/**
 * @file init.c
 * @brief
 * @author h0rr0rr_drag0n <h0rr0rr_drag0n@vindekapets.ru
 * @date 01 Июль 2010 20:36:42
 *
 * Initial code
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <syslog.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "define.h"

extern volatile int child_flag;
extern volatile int abort_flag;

/**
 * @brief SIGCHLD handler
 *
 * This function set special flag when SIGINT or SIGQUIT comes
 */
void abort_handler() {
    sigset_t blockset;
    if (sigemptyset(&blockset) != 0) {
        return;
    }
    if (sigaddset(&blockset, SIGQUIT) != 0) {
        return;
    }
    if (sigaddset(&blockset, SIGINT) != 0) {
        return;
    }
    if (sigprocmask(SIG_BLOCK, &blockset, NULL) != 0) {
        return;
    }
    abort_flag = 1;
    if (sigprocmask(SIG_UNBLOCK, &blockset, NULL) != 0) {
        return;
    }

    return;
}

/**
 * @brief SIGCHLD handler
 *
 * This function set special flag when SIGCHLD comes
 */
void child_handler() {
    sigset_t blockset;
    if (sigemptyset(&blockset) != 0) {
        return;
    }
    if (sigaddset(&blockset, SIGCHLD) != 0) {
        return;
    }
    if (sigprocmask(SIG_BLOCK, &blockset, NULL) != 0) {
        return;
    }
    child_flag = 1;
    if (sigprocmask(SIG_UNBLOCK, &blockset, NULL) != 0) {
        return;
    }

    return;
}

/**
 * @brief Setting up signal handlers.
 *
 * This function setting up signal handlers for:
 * #SIGING, SIGQUIT - for clearly stop execution
 * #SIGCHLD
 *
 * @retval 0 in success; non-zero on error
 */
int setup_sighandlers() {
    struct sigaction child_act;
    struct sigaction abort_act;

    if (memset(&child_act, 0, sizeof(child_act)) == NULL) {
        syslog(LOG_ERR, "Error: memset(): child_act");
        return 1;
    }
    if (memset(&abort_act, 0, sizeof(abort_act)) == NULL) {
        syslog(LOG_ERR, "Error: memset(): abort_act");
        return 1;
    }
    child_act.sa_handler = child_handler;
    abort_act.sa_handler = abort_handler;

    if (sigaction(SIGINT, &abort_act, NULL) < 0) {
        syslog(LOG_ERR, "Error: sigaction(): cannot set SIGINT handler");
        return 1;
    }
    if (sigaction(SIGQUIT, &abort_act, NULL) < 0) {
        syslog(LOG_ERR, "Error: sigaction(): cannot set SIGQUIT handler");
        return 1;
    }
    if (sigaction(SIGCHLD, &child_act, NULL) < 0) {
        syslog(LOG_ERR, "Error: sigaction(): cannot set SIGCHLD handler");
        return 1;
    }

    return 0;
}

/**
 * @brief Function to make clean at exit
 *
 * This function make clean - close log file, 
 * remove pipe and etc.
 */
void emerg_exit() {
    closelog();
    unlink(FIFO_PATH);
    exit(0);
}

/**
 * @brief Main initial function
 *
 * Main initial function for osd_server calls all another initial functions 
 * in this file
 *
 * @param [in] daemonize Run as daemon (1) or not (0)
 *
 * @retval 0 on success; non-zero value on error
 */
int osd_slider_init(int daemonize) {
    if (mkfifo(FIFO_PATH, FIFO_PERM)) {
        fprintf(stderr, "Error: mkfifo(), %s : %s\n", FIFO_PATH,
                strerror(errno));
        return 1;
    }

    if (daemonize) {
        if (chdir("/tmp")) {
            fprintf(stderr, "Error: chdir(): %s\n", strerror(errno));
            return 1;
        }
        if (daemon(0, 0)) {
            fprintf(stderr, "Error: daemon(): %s\n", strerror(errno));
            return 1;
        }
    }

    openlog("osd_server", LOG_PID, LOG_DAEMON);

    if (setup_sighandlers()) {
        return 1;
    }

    return 0;
}

